#pragma once

#include "LoggedTestSuite.h"

/*

|-----------|     |-----------|
|           |  _  |           |
| back     |1|\ /|b1| front   | /|p1|
| object    |  X  |   object |f|
|          |2|/_\|b2|         | \|p2|
|           |     |           |
|-----------|     |-----------|

Test Cases
00 - Check port bindings.
01 - Pi-f-pi.  Test reply to portal send.
02 - p1-f-b1-1-back.  Test reply to AO send.
03 - Pi-f-pi.  Test reply to portal invoke.
04 - Pi-f-pi.  Test timeout to portal invoke.
05 - Pi-f-pi.  Test reply to AO invoke.
06 - Pi-f-pi.  Test timeout to AO invoke.
11 - Message from p1-f-b1-1-back the same route.
1B - 11, but broadcasted back.
B1 - Broadcast out, single path back
BB - Broadcast out, broad cast back.
*R - Previous with objects bound remotely.

*/

namespace CO { namespace SpiFoundation { namespace RoomFW {

enum // ContractTypeId
{
	CTID_TEST = CTID_BASE
};

enum // ObjectId
{
	OID_FRONT = OID_BASE,
	OID_BACK
};

class TestProtocol : public ContractChecker
{
public:
	TestProtocol(bool conjugate) : ContractChecker(conjugate) {}
	virtual ContractTypeId getTypeID() const { return CTID_TEST; }
	virtual bool validMessage(MessageID messageID, const IPayloadSP& payload) const;
	virtual const char* messageName(MessageID messageID) const;
	virtual IContractCheckerSPC getConjugate(void) const { return IContractCheckerSPC(new TestProtocol(!this->isConjugate())); }
	virtual IPayloadSP createPayload(MessageID /*messageID*/) const { return IPayloadSP(); }

	enum MessageIds
	{
		TEST00,
		TEST01,
		TEST02,
		TEST03,
		TEST04,
		TEST05,
		TEST06,
		TEST11,
		TEST1B,
		TESTB1,
		TESTBB,
		PASS,
		FAIL
	};
};

class FrontObject : public ActiveObject
{
public:
	enum PortEnum 
	{
		PORT_FRONT,
		PORT_BACK1,
		PORT_BACK2,
		PORT_COUNT
	};
	static const PortPriority PortPriorities[];
	static const size_t PortPrioritiesSize;

	FrontObject(void);
	~FrontObject(void);
	void reset(void);

	virtual IContractCheckerSPC getContractChecker(PortIndex portIndex) const;
	virtual ObjectId getObjectId(void) const { return OID_FRONT; }
	virtual const char* getObjectName(void) const { return "FrontObject"; }
	virtual const char* getPortName(size_t portIndex) const;

protected:
	virtual void handle(RoomMessageSP message);

private:
	TestProtocol testProtocol_;
	TestProtocol testProtocolStar_;
	TestProtocol::MessageIds testCase_;
	bool pass1_;
	bool pass2_;
	RoomTimer::TimerId timerId_;
	TimeValue timeout_;
};

class BackObject : public ActiveObject
{
public:
	enum PortEnum 
	{
		PORT_1,
		PORT_2,
		PORT_COUNT
	};
	static const PortPriority PortPriorities[];
	static const size_t PortPrioritiesSize;

	BackObject(void);
	~BackObject(void);
	void reset(void);

	virtual IContractCheckerSPC getContractChecker(PortIndex portIndex) const;
	virtual ObjectId getObjectId(void) const { return OID_BACK; }
	virtual const char* getObjectName(void) const { return "BackObject"; }
	virtual const char* getPortName(size_t portIndex) const;

protected:
	virtual void handle(RoomMessageSP message);

private:
	TestProtocol testProtocol_;
	TestProtocol::MessageIds testCase_;
	bool pass1_;
	bool pass2_;
	RoomTimer::TimerId timerId_;
	TimeValue timeout_;
};

class ActiveObjectPortTestSuite : public LoggedTestSuite
{
public:
	ActiveObjectPortTestSuite();
	~ActiveObjectPortTestSuite();

protected:

	virtual void setup();
	virtual void tear_down();

private:
	void test00(void);
	void test01(void);
	void test02(void);
	void test03(void);
	void test04(void);
	void test05(void);
	void test06(void);
	void test11(void);
	void test1B(void);
	void testB1(void);
	void testBB(void);

	EventPortal portal1_;
	EventPortal portal2_;
	FrontObject frontObject_;
	BackObject backObject_;
	BindingList bindings_;

};

}}}
